Repository navigation
fix(formula): an advisory validation rule's date verdict says the rule is skipped and the write proceeds - #30585
Conversation
…lative sweep sentence (red) Claude-Session: https://claude.ai/code/session_01Utp6CbntgiC5D1vTyg2pBV Co-authored-by: Claude <noreply@anthropic.com>
…efused; a sweep's run-fails verdict names no firing write Claude-Session: https://claude.ai/code/session_01Utp6CbntgiC5D1vTyg2pBV Co-authored-by: Claude <noreply@anthropic.com>
… three codes Claude-Session: https://claude.ai/code/session_01Utp6CbntgiC5D1vTyg2pBV Co-authored-by: Claude <noreply@anthropic.com>
…to claude/project-thread-r6w6jd
…open sentence (red) Claude-Session: https://claude.ai/code/session_01Utp6CbJFWadws6f9r4B8Ke Co-authored-by: Claude <noreply@anthropic.com>
…d and the write proceeds On a fail-open site (a warning / info validation rule) the date-arithmetic and date-text-arithmetic verdicts close on the type-mismatch-fail-open clause, under their own codes date-arithmetic-fail-open and date-text-arithmetic-fail-open. The grade stays an error; a formula field keeps date-arithmetic and its null sentence. Claude-Session: https://claude.ai/code/session_01Utp6CbJFWadws6f9r4B8Ke Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Utp6CbJFWadws6f9r4B8Ke Co-authored-by: Claude <noreply@anthropic.com>
…-r6w6jd # Conflicts: # packages/formula/src/expression-refusal-codes.test.ts # packages/formula/src/expression-refusal.ts # packages/formula/src/validate.test.ts # packages/formula/src/validate.ts # packages/lint/src/validate-expressions.test.ts
📓 Docs Drift Check5 anchor(s) derived from 1 changed package(s); no hand-written page names any of them, so this run has nothing to list — not a clean bill of health. This check sees only pages that NAME a derived anchor: one that documents this change in prose, or enumerates it in an authoring dialect, names none and stays invisible to it on every run. What this run could not see
Coarse fallback — 11 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 7886a3daa57310c24e3764b14ffb1012e8350df9 && git checkout 7886a3daa57310c24e3764b14ffb1012e8350df9
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 2ffdb649775d20313707d88a8388275f280a0a7f dfc91e9df6c84797eb6c6f03451d60a62839814b && git checkout -B drift-repro 2ffdb649775d20313707d88a8388275f280a0a7f && git merge --no-ff dfc91e9df6c84797eb6c6f03451d60a62839814b
node scripts/docs-audit/affected-docs.mjs --json 2ffdb649775d20313707d88a8388275f280a0a7f |
|
domain:server#5 · os-bill · session_01Utp6CYVV6fcAQrNTDQRvPb Contract reviewServed-tier: ① Derived judgments
② Semver level
③ Boundary flags
Implemented-by: VERDICT: PASS |
|
domain:server#5 · os-bill · session_01Utp6CYVV6fcAQrNTDQRvPb 维护者速读
席位意见:同意落地。这是放宽型改动(新增两个码),declaration 面记录 PASS(6663771132),钉住 head 席位核对Head
|
Requested by Bill · project thread
domain:server#5 · os-bill · session_01Utp6CYVV6fcAQrNTDQRvPb
维护者速读
severity: 'warning'/'info')里对日期做加减时,报错不再说「字段静默得到 null」,改说「规则被跳过、写入照常进行、只留一行日志」,配新码date-arithmetic-fail-open/date-text-arithmetic-fail-open,文案与同位置的类型不匹配判词一字不差。date-arithmetic/date-text-arithmetic识别 advisory 规则的使用方需改认新码。公式字段原码原句不动。回滚即 revert,无数据迁移。packages/formula/src/validate.ts的dateArm与dateArmFault(fail-open分支),packages/formula/src/expression-refusal.ts的两个新码。pnpm --filter @objectstack/lint exec vitest run src/validate-expressions.test.ts -t 30494,预期 1 条通过:warning / info 规则的日期判词说规则被跳过、写入照常,不含 null;公式字段对照仍说 null。Fixes #30494
Clause-②: yes (widening) — two codes join
@objectstack/formula's exportedExpressionRefusalCode/EXPRESSION_REFUSAL_CODES:date-arithmetic-fail-openanddate-text-arithmetic-fail-open, each with the params of the code it splits from. An advisory rule's date verdicts move to them fromdate-arithmetic/date-text-arithmetic(a consumer keyed to the old codes on an advisory rule re-keys). The grade is unchanged; what is refused, warned or passed is unchanged.Metadata-protocol: none — what an author can write is unchanged, and
os validatereports no expression refusal code: its findings are@objectstack/lint'sExprIssue(where,message,source,severity,path), re-measured atpackages/lint/src/validate-expressions.ts:157, which carries nocode. Only the message text changes there.Skills-docs: none —
git grep -c "silently evaluates to null" -- skillsanswers no hit (exit 1); control:git grep -c "evaluates to" -- skillshitsskills/objectstack-automation/SKILL.md,skills/objectstack-data/SKILL.mdandskills/objectstack-data/rules/validation.md, none of them about a date verdict on an advisory rule.What changes
Measured on
mainwith PR #30492 merged (67d5d5375), and again afterorigin/mainwas merged ata4c3e738.warning/info) validation rule (faultOutcome: 'fail-open'): date arithmeticdate-arithmetic/date-text-arithmetic, error, "this faults at runtime, so the field silently evaluates to null."date-arithmetic-fail-open/date-text-arithmetic-fail-open, error: "this faults at runtime, and here the rule is advisory, so a rule that cannot be evaluated is skipped, not refused: the write proceeds, the rule is never applied (its advisory never fires), and the only trace is a log line saying it could not be evaluated."date-arithmetic/date-text-arithmetic-fail-closed/-run-fails/-run-may-failcodesdateArmFaultcloses thefail-openarm onTYPE_MISMATCH_FAULT_ARMS['fail-open'].clauseitself, not a copy, so the date verdict and the type-mismatch verdict on the same rule cannot drift apart.expression-refusal.tsis the contract that a code names one message template.@objectstack/lint'sfaultOutcomeOfledger already answersfail-openfor awarning/inforule (validate-expressions.ts:1358), and MCPvalidate_expressionalready passes it forsite: 'validation'withseverity: 'warning' | 'info'(mcp-http-tools.ts:666). Neither package changes.Tests
packages/formula/src/validate.test.ts:fail-openrecordsite,record.start_date + 1 > 3andrecord.end_date - record.start_date > duration("24h")get the-fail-opencodes and the fail-open sentence, and not "evaluates to null". Control: the same two predicates with no outcome keepdate-arithmetic/date-text-arithmeticand the null sentence;date-arithmeticand the null sentence, which is this card's defect. That row is dropped; its formula-field controls stay.packages/formula/src/expression-refusal-codes.test.ts: aPINSentry for each new code (exact params and message), andSWEEP_SCHEMASgains thefail-opendate schema, so the sweep reaches both codes and holds their params to their messages.packages/lint/src/validate-expressions.test.ts, new: awarningrule and aninforule with date arithmetic say the rule is skipped and the write proceeds (not null, not refused). Control: a formula field'srecord.close_date + 1keeps the null sentence.packages/mcp/src/mcp-validate-expression.test.ts: unchanged, verbatim. Measured once with a probe file that was deleted afterwards (not committed):validate_expressionatsite: 'validation'answersdate-arithmetic-fail-open/date-text-arithmetic-fail-openforseverity: 'warning'and'info',-fail-closedfor'error', anddate-arithmeticatsite: 'formula'; each message equalsvalidateStackExpressions' on the same rule.Suites and red-first
Ablation (scripts/ablation-replace.mjs; restored: blob == HEAD, git diff HEAD empty, dist marker absent after rebuild, tree clean)
Acceptance notes
packages/lint/src/validate-expressions.ts:1338-1341doc comment names the date verdicts'-run-fails,-run-may-failand-fail-closedarms and not the new-fail-openone. It says nothing false (it never says an advisory rule keeps the null sentence), andpackages/lint/src/**source is outside this card's file surface, so it is left as is..changeset/30250-fail-closed-date-and-sweep-run-fails-sentences.md) says an advisory rule keepsdate-arithmetic/date-text-arithmetic. Both changesets ship in the same release; this PR's changeset says it replaces that note, and the other file is not edited here.content/docs/data-modeling/formulas.mdxdate-arithmetic row says "this always faulted tonull". That describes a formula's runtime, and this PR changes no runtime, so it is left as is (as formula: two refusal sentences say what does not happen at their site (fail-closed validation date verdict says "null"; run-fails on a time-relative sweep says "the write still lands") #30250 left it).origin/mainwas merged once ata4c3e738. The branch had carried PR fix(formula,lint,mcp): a fail-closed date verdict says the write is refused, and a time-relative sweep's run-fails verdict names no firing write #30492's head as a merge until it landed as a squash, so git reported conflicts in the five files both sides touch. They were resolved by applying this branch's own diff (ebda9aca..34b93ec4) toorigin/main's copies: it applied cleanly, and the changed lines of the resolved delta are identical to that diff's.Verification
All at head
dfc91e9d(git rev-parse --short HEAD), the commit this PR opens on (origin/mainmerged once, ata4c3e738).pnpm install --frozen-lockfile && turbo run build --filter='!@objectstack/docs' --concurrency=2, 119/119 tasks,VERDICT command-exit 0.node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack: change set of 6 paths vs merge basea4c3e738b, 58 derived families, each run on this head, all exit 0 (each exit code recorded before any pipe).check-plugin-teardown-shape.mjs --self-testran after fetching its pinned fixture commit621a4876into the shallow clone ("48 cases pass").--ran: "58 derived famil(ies) accounted for — 58 run, 0 NOT-MEASURED". Among themcheck-adr-0087-registration --base origin/main,check-changeset-no-major,check-empty-changeset,check:doc-authoring,check:docs-transcript-drift,check:test-source-alias,check:cross-package-test-inputs,check:dts-closure,check:dual-build-cjs-loads,check:lean-entry-closure,check:nul-bytes,check:closing-keyword-parity.pnpm lint(eslint . --no-inline-config): exit 0.!andClause-②has no(narrowing)arm.🤖 Generated with Claude Code
https://claude.ai/code/session_01Utp6CbJFWadws6f9r4B8Ke